#include "Kernels.h"

/*--------------------------------------------------------------------------------------
 *    Function:  calcWordProb
 * Description:  Calcula a probabilidade acumulada
 *--------------------------------------------------------------------------------------
 */
void getWordProb(HostProb &accProb, uint maxSize)
{
    // Cria um vetor com potências de 26 e inicializa
    ulong pow26[_WD_SIZE + 1];
    pow26[0] = pow26[1] = 0, pow26[2] = 26 * 26;

    ulong sum = pow26[2];

    // Atribui as potências e calcula a soma
    for(uint i = 3; i < _WD_SIZE + 1; i++)
    {
        pow26[i] = pow26[i-1] * 26;
        sum += pow26[i];
    }

    // Inicializa as de tamanho 0 e 1 como 0
    accProb[0] = accProb[1] = 0;

    for(uint i = 2; i < _WD_SIZE + 1; i++)
    {
        // Calcula a probabilidade
        double prob = pow26[i] / (double) sum;

        // Multiplica pela máximo valor gerado pela função aleatória
        accProb[i] = round(prob * maxSize + accProb[i-1]);
    }
}

/*--------------------------------------------------------------------------------------
 *    Function:  seqGenerateWord
 * Description:  Gera uma palavra aleatória
 *--------------------------------------------------------------------------------------
 */
void seqGenerateWord(Word genWord, uint* accProb)
{
    // Gera um número aleatório
    uint r = rand();

    // Escolhe um tamanho aleatório
    uint len;
    for(len = _WD_SIZE; r < accProb[len - 1]; len--);

    // Escolhe aleatoriamente os caracteres
    for(uint i = 0; i < len; i++)
        genWord[i] = rand() % 26 + 'a';

    // Insere '\0'
    genWord[len] = '\0';
}

/*--------------------------------------------------------------------------------------
 *    Function:  seqCheckWord
 * Description:  Verifica se acertou uma palavra
 *--------------------------------------------------------------------------------------
 */
void seqCheckWord(Word genWord, WordPair* dict, uint dictSize, uint* hits)
{
    // Inicializa a busca binária
    uint a = 0, b = dictSize - 1, m;

    // Enquanto for um intervalo válido
    while(a <= b)
    {
        // Pega o meio
        m = (a + b) / 2;

        // Compara com a palavra do meio
        int cmp = wordCompare(genWord, dict[m].word);

        // Se for menor
        if(cmp < 0)
            b = m - 1;
        // Se for maior
        else if(cmp > 0)
            a = m + 1;
        // Se acertou
        else
        {
            if(!dict[m].hasFound)
                dict[m].hasFound = 1, (*hits)++;
            break;
        }
    }
}

/*--------------------------------------------------------------------------------------
 *    Function:  seqCountHits
 * Description:  Verifica se acertou uma plavara gerada aleatóriamente
 *--------------------------------------------------------------------------------------
 */
int seqCountHits(HostWordPair &hostDict, uint *hostHits, HostProb &hostProb)
{
    for(uint i = 0; i < BLOCK_SIZE; i++)
    {
        // Gera uma palavra aleatória
        Word genWord;
        seqGenerateWord(genWord, hostProb.data());

        // Verifica quantas acertaram
        seqCheckWord(genWord, hostDict.data(), hostDict.size(), hostHits);
    }

    return *hostHits;
}
